package oboe.utils;

import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.utils.ByteArray;
import flash.utils.Endian;
class HSLA
{
public var h : Float;
public var s : Float;
public var l : Float;
public var a : Float;

public function toString() : String {
	return "H: " + h + ", S: " + s + ", L:" + l + ", A:" + a;
}

public static inline var LUMINANCE : UInt = 1;
public static inline var SATURATION : UInt = 2;
public static inline var HUE : UInt = 4;
public static inline var ALL : UInt = 7;

public function new() { }

public function toARGB() : UInt {
	var r : Float, g : Float, b : Float;
	if ( s == 0 ) {
	r = g = b = l;
	}else {
	var t2 : Float;
	if ( l < 0.5 ) t2 = l * (1.0 + s);
	else t2 = l + s - l * s;
	var t1 : Float = 2.0 * l - t2;

	var t3 : Float = h + 1.0 / 3.0;
	if ( t3 < 0 ) t3++;
	else if ( t3 > 1 ) t3--;
	if ( t3 * 6.0 < 1 ) r = t1 + (t2 - t1) * 6.0 * t3;
	else if ( t3 * 2.0 < 1 ) r = t2;
	else if ( t3 * 3.0 < 2 ) r = t1 + (t2 - t1) * ((2.0 / 3.0) - t3) * 6.0;
	else r = t1;

	t3 = h;
	if ( t3 < 0 ) t3++;
	else if ( t3 > 1 ) t3--;
	if ( t3 * 6.0 < 1 ) g = t1 + (t2 - t1) * 6.0 * t3;
	else if ( t3 * 2.0 < 1 ) g = t2;
	else if ( t3 * 3.0 < 2 ) g = t1 + (t2 - t1) * ((2.0 / 3.0) - t3) * 6.0;
	else g = t1;
	
	t3 = h - 1.0 / 3.0;
	if ( t3 < 0 ) t3++;
	else if ( t3 > 1 ) t3--;
	if ( t3 * 6.0 < 1 ) b = t1 + (t2 - t1) * 6.0 * t3;
	else if ( t3 * 2.0 < 1 ) b = t2;
	else if ( t3 * 3.0 < 2 ) b = t1 + (t2 - t1) * ((2.0 / 3.0) - t3) * 6.0;
	else b = t1;
	}
	return (uint(a*255.0)<<24) + (uint(r*255.0)<<16) + (uint(g*255.0)<<8) + uint(b*255.0);
}

public static function colorBitmapU32( bd : BitmapData, rgb : UInt , scaleLum : Bool, reference:UInt = 0 ) : Void {
	colorBitmap( bd, (rgb>>16)&0xFF, (rgb>>8)&0xFF, rgb&0xFF, scaleLum, reference );
}

public static function colorBitmap( bd : BitmapData, r : UInt, g : UInt, b : UInt, scaleLum : Bool, reference : UInt = 0 ) : Void {
	var target : HSLA = fromARGB( 0xFF, r, g, b );
	var rect : Rectangle = new Rectangle(0, 0, bd.width, bd.height);
	var inp : ByteArray = bd.getPixels( rect );
	var out : ByteArray = new ByteArray();
	var cur : HSLA;
	var u : UInt;
	out.length = inp.length;
	out.endian = Endian.LITTLE_ENDIAN;
	inp.position = 0;
	var ref : HSLA;
	if( !reference ) ref = fromU32( inp.readUnsignedInt(), LUMINANCE + HUE );
	else ref = fromU32( reference, LUMINANCE + HUE );
	target.l = (target.l * 0.8) / ref.l;
	inp.position = 0;
	out.position = 0;
	if( scaleLum ){
	while ( inp.position != inp.length ) {
		cur = fromU32( inp.readUnsignedInt() );
		if( cur.s )
		{
		cur.l *= target.l;
		if ( cur.l > 1 ) cur.l = 1;
		cur.h += target.h - ref.h;
		// cur.s = target.s/ref.s;
		if ( cur.h < 0 ) cur.h++;
		else if ( cur.h > 1 ) cur.h--;
		out.writeUnsignedInt(cur.toARGB());
		}
	}
	}else {
	while ( inp.position != inp.length ) {
		cur = fromU32( inp.readUnsignedInt() );
		if( cur.s )
		{
		cur.h += target.h - ref.h;
		// cur.s = target.s - ref.s;
		
		if ( cur.h < 0 ) cur.h++;
		else if ( cur.h > 1 ) cur.h--;
		out.writeUnsignedInt(cur.toARGB());
		}
	}
	}
	out.position = 0;
	bd.setPixels( rect, out );
}

public static function getLuma( r : UInt, g : UInt, b : UInt ) : Float {
	var max : Float = r;
	var min : Float = g;
	if ( g > r ) {
	max = g;
	min = r;
	}
	if ( b > max ) 	max = b;
	else if ( b < min ) min = b;
	return (max + min) / 2;
} 

public static function fromU32( u : UInt, components : UInt = ALL ) : HSLA {
	return fromARGB( u>>24, u>>16, u>>8, u, components  );
}
public static function fromARGB( a : UInt, r : UInt, g : UInt, b : UInt, components : UInt = ALL ) : HSLA {
	return fromNormalizedARGB( (a&0xFF)/255.0, (r&0xFF)/255.0, (g&0xFF)/255.0, (b&0xFF)/255.0, components );
}
public static function fromNormalizedARGB( a : Float, r : Float, g : Float, b : Float, components : UInt = ALL ) : HSLA {
	var hsl : HSLA = new HSLA();
	hsl.s = hsl.h = 0;
	if ( components == 0 ) return hsl;
	hsl.a = a;
	var max : Float = r;
	var min : Float = g;
	if ( g > r ) {
	max = g;
	min = r;
	}
	if ( b > max ) 	max = b;
	else if ( b < min ) min = b;
	var mmd : Float = max - min;
	
	hsl.l = (max + min) / 2;
	if ( max == min || components == LUMINANCE ) return hsl;
	if ( (components & SATURATION) != 0 ){
	if ( hsl.l < 0.5 ) hsl.s = mmd / (max + min);
	else hsl.s = mmd / (2.0 - mmd);
	}
	if ( (components & HUE) != 0 ){
	if ( r == max ) hsl.h = (g - b) / mmd;
	else if ( g == max ) hsl.h = 2.0 + (b - r) / mmd;
	else hsl.h = 4.0 + (r - g) / mmd;
	hsl.h /= 6.0;
	if ( hsl.h < 0 ) hsl.h++;
	}
	return hsl;
}
}